package tools.yangkl.utils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author yangkl
 * @since 2022/11/30
 **/
public class TimeUtils {
    private TimeUtils() {

    }

    @Data
    @EqualsAndHashCode
    @AllArgsConstructor
    public static class TimeIntersection {
        Date start;
        Date end;

        public void check() {
            if (null == start || null == end) {
                throw new IllegalArgumentException("参数错误：时间参数为null");
            }
            if (start.after(end)) {
                throw new IllegalArgumentException("参数错误：start应该小于等于end");
            }
        }
    }

    /**
     * 获取时间集合的交集
     *
     * @param dates 时间集合
     * @return 交集
     */
    public static TimeIntersection intersection(List<TimeIntersection> dates) {
        if (CollectionUtils.isEmpty(dates)) {
            return null;
        }
        // 1.每个time的start<=end校验
        for (TimeIntersection time : dates) {
            time.check();
        }
        if (dates.size() == 1) {
            return dates.get(0);
        }
        // 2.按照start时间排序，保证开始时间小的在前面
        boolean existOverlap = existOverlap(dates);
        if (!existOverlap) {
            return null;
        }
        Date maxStart = dates.get(dates.size() - 1).getStart();
        List<Date> allEndDate = dates.stream().map(TimeIntersection::getEnd).collect(Collectors.toList());
        Collections.addAll(allEndDate, maxStart);
        Collections.sort(allEndDate);
        Date minStart = allEndDate.get(0);
        Optional.of(dates).get().sort((o1, o2) -> CommonUtils.compare(o1.end, o2.end));
        Date minEnd = dates.get(0).getEnd();
        return new TimeIntersection(minStart, minEnd);
    }

    /**
     * 获取时间集合的并集
     *
     * @param dates 时间集合
     * @return 并集
     */
    public static TimeIntersection union(List<TimeIntersection> dates) {
        if (CollectionUtils.isEmpty(dates)) {
            return null;
        }
        // 1.每个time的start<=end校验
        for (TimeIntersection time : dates) {
            time.check();
        }
        if (dates.size() == 1) {
            return dates.get(0);
        }
        Optional.of(dates).get().sort((o1, o2) -> CommonUtils.compare(o1.start, o2.start));
        Date minStart = dates.get(0).getStart();
        Optional.of(dates).get().sort((o1, o2) -> CommonUtils.compare(o1.end, o2.end));
        Date maxEnd = dates.get(dates.size() - 1).end;
        return new TimeIntersection(minStart, maxEnd);
    }

    /**
     * 判断时间集合中是否有交集
     *
     * @param dates 时间集合
     * @return true/false
     */
    public static boolean existOverlap(List<TimeIntersection> dates) {
        Optional.of(dates).get().sort((o1, o2) -> CommonUtils.compare(o1.start, o2.start));
        boolean existOverlap = false;
        for (int i = 1; i < dates.size(); i++) {
            TimeIntersection current = dates.get(i);
            TimeIntersection previous = dates.get(i - 1);
            // 当前时段小的在下一个时段的小的之后，有交集
            existOverlap = existOverlap(current, previous);
            if (!existOverlap) {
                break;
            }
        }
        return existOverlap;
    }

    /**
     * @param current  当前时间模型
     * @param previous 上一个时间模型
     * @return 两个时间模型是否存在交集
     */
    public static boolean existOverlap(TimeIntersection current, TimeIntersection previous) {
        return (previous.getEnd().compareTo(current.getStart()) >= 0);
    }
}
